#include <iostream>
#include <memory>
#include <functional>
#include "tcpserver.hpp"
#include "protocol.hpp"
#include "calculate.hpp"

void Usage(std::string proc)
{
    std::cout << "Usage:" << proc << "port" << std::endl;
}

using cal_t = std::function<Result(const Request &req)>;

class CalServer
{
public:
    CalServer(cal_t cal) : _cal(cal)
    {
    }

    void server(net::socket_ptr sockptr, InetAddr addr)
    {
        Log(DEBUG, "get a new link:%s %d", addr.ip().c_str(), addr.port());
        std::string clientaddr = "[" + addr.ip() + ":" + std::to_string(addr.port()) + "]#";
        std::string inbuffer;
        while (true)
        {
            // 1、读取数据
            int n = sockptr->Recv(&inbuffer);
            Request request;
            // 2、分析数据
            if (n > 0) // 读成功了
            {
                std::string package = DeCode(inbuffer);
                if (package.empty()) // inbuffer中没有一个完整的报文
                {
                    continue;
                }
                // 读到了一个完整的json串
                // 对报文进行反序列化
                request.deserialization(package);
                std::cout << "package:" << package << std::endl;
                // 业务处理
                Result result = _cal(request);
                std::cout << "result:" << result.get_result() << ' ' << "code:" << result.get_code() << std::endl;
                // 得到结果之后对结果进行序列化
                std::string send_str;
                result.serialize(&send_str);
                // std::cout<<"result:"<<send_str<<std::endl;
                // 序列化之后在对其添加报头
                send_str = EnCode(send_str);
                // 反序列化之后再将结果发回去
                sockptr->Send(send_str);
            }
            else
            {
                Log(DEBUG, "client:[%s] quit", clientaddr.c_str());
                break;
            }
        }
    }

private:
    cal_t _cal;
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 0;
    }
    uint16_t port = std::stoi(argv[1]);
    Calculate calculte;//应用层
    CalServer calserver(std::bind(&Calculate::Excute, &calculte, std::placeholders::_1));//表示层
    std::unique_ptr<tcpserver> ts = std::make_unique<tcpserver>(port, std::bind(&CalServer::server, &calserver, std::placeholders::_1, std::placeholders::_2));//会话层
    ts->start();
    return 0;
}
